﻿using huqiang.Core.HGUI;
using huqiang.Data;
using huqiang.UIComposite;
using huqiang.UIEvent;
using ILRuntime.CLR.Method;
using ILRuntime.CLR.TypeSystem;
using System;
using System.IO;
using UnityEngine;
using Fixed.ILRunTime;
using ProtoBuf;
using huqiang.Framework;

public class HotFix
{
    static HotFix ins;
    static ILRuntime.Runtime.Enviorment.AppDomain _app;
    public static HotFix Instance { get { if (ins == null) ins = new HotFix(); return ins; } }

    static object PType_CreateInstance(string typeName)
    {
        return _app.Instantiate(typeName);
    }

    static Type PType_GetRealType(object o)
    {
        var type = o.GetType();
        if (type.FullName == "ILRuntime.Runtime.Intepreter.ILTypeInstance")
        {
            var ilo = o as ILRuntime.Runtime.Intepreter.ILTypeInstance;
            type = ProtoBuf.PType.FindType(ilo.Type.FullName);
        }
        return type;
    }

    ILType mainScript;
    IMethod start;
    IMethod Update;
    IMethod Cmd;
    IMethod FullCmd;
    IMethod Resize;
    IMethod Dispose;
    byte[] dll;
    MemoryStream dllStream;
    MemoryStream pdbStream;
    private HotFix()
    {
        _app = new ILRuntime.Runtime.Enviorment.AppDomain();
        _app.DebugService.StartDebugService(7000);
        RegDelegate();
        RegProtobuf();
        ILRuntime.Runtime.Generated.CLRBindings.Initialize(_app);
    }
    public void LoadDll()
    {
        if (dllStream != null)
            dllStream.Dispose();
        if (pdbStream != null)
            pdbStream.Dispose();
        if (LocalSetting.IsEditor)
        {
            LoadFromProject();
        }
        else 
        {
            if (!LoadFromAssetsbundle())
                LoadFromProject();
        }
    }
    void LoadFromProject()
    {
        dllStream = new MemoryStream(File.ReadAllBytes("Library/ScriptAssemblies/HotFix.dll"));
        pdbStream = new MemoryStream(File.ReadAllBytes("Library/ScriptAssemblies/HotFix.pdb"));
    }
    bool LoadFromAssetsbundle()
    {
        string path = AssetsVersionControl.GetAssetsPath("hotfix");
        if(File.Exists(path))
        {
            AssetBundle ab = AssetBundle.LoadFromFile(path);
            var dll = ab.LoadAsset<TextAsset>("hotfix.dll.bytes");
            if (dll != null)
                dllStream = new MemoryStream(dll.bytes);
#if DEBUG
            var pdb = ab.LoadAsset<TextAsset>("hotfix.pdb.bytes");
            if (pdb != null)
                pdbStream = new MemoryStream(pdb.bytes);
#endif
            ab.Unload(true);
            return true;
        }
        return false;
    }
    public void Initial()
    {
        if (pdbStream != null)
        {
            ///api compatibility level 请使用.Net 4.x否则会报错
            _app.LoadAssembly(dllStream, pdbStream, new ILRuntime.Mono.Cecil.Pdb.PdbReaderProvider());
        }
        else
        {
            _app.LoadAssembly(dllStream);
        }
        mainScript = _app.GetType("Main") as ILType;
        start = mainScript.GetMethod("Start");
        Update = mainScript.GetMethod("Update");
        Resize = mainScript.GetMethod("Resize");
        Cmd = mainScript.GetMethod("Cmd");
        FullCmd = mainScript.GetMethod("FullCmd");
        Dispose = mainScript.GetMethod("Dispose");
    }
    void RegDelegate()
    {
        _app.DelegateManager.RegisterMethodDelegate<byte[], byte>();
        _app.DelegateManager.RegisterMethodDelegate<object>();
        _app.DelegateManager.RegisterMethodDelegate<object, object, int>();
        _app.DelegateManager.RegisterMethodDelegate<object, object, float>();
        _app.DelegateManager.RegisterMethodDelegate<UIElement>();
        _app.DelegateManager.RegisterMethodDelegate<UserEvent, UserAction>();
        _app.DelegateManager.RegisterMethodDelegate<UserEvent, UserAction, Vector2>();
        _app.DelegateManager.RegisterMethodDelegate<InputBox>();
        _app.DelegateManager.RegisterMethodDelegate<GestureEvent>();

        _app.DelegateManager.RegisterMethodDelegate<UIRocker>();
        _app.DelegateManager.RegisterMethodDelegate<UISlider>();
        _app.DelegateManager.RegisterMethodDelegate<ScrollItem>();
        _app.DelegateManager.RegisterMethodDelegate<ScrollX>();
        _app.DelegateManager.RegisterMethodDelegate<ScrollX, Vector2>();
        _app.DelegateManager.RegisterMethodDelegate<ScrollY>();
        _app.DelegateManager.RegisterMethodDelegate<ScrollY, Vector2>();
        _app.DelegateManager.RegisterMethodDelegate<DragContent>();
        _app.DelegateManager.RegisterMethodDelegate<DragContent, Vector2>();
        _app.DelegateManager.RegisterMethodDelegate<GridScroll>();
        _app.DelegateManager.RegisterMethodDelegate<GridScroll, Vector2>();
        _app.DelegateManager.RegisterMethodDelegate<DropdownEx, object>();
        _app.DelegateManager.RegisterMethodDelegate<ScrollYExtand, Vector2>();
        _app.DelegateManager.RegisterMethodDelegate<ObjectLinker, LinkerMod>();
        _app.DelegateManager.RegisterMethodDelegate<UIContainer>();
        _app.DelegateManager.RegisterMethodDelegate<OptionGroup, UserAction>();
        _app.DelegateManager.RegisterMethodDelegate<TreeView, TreeViewItem>();
        _app.DelegateManager.RegisterMethodDelegate<TreeViewItem, TreeViewNode>();
        _app.DelegateManager.RegisterMethodDelegate<UIPalette>();

        _app.DelegateManager.RegisterMethodDelegate<IMission>();
        _app.DelegateManager.RegisterMethodDelegate<AsyncOperation>();

        _app.DelegateManager.RegisterFunctionDelegate<object>();
        _app.DelegateManager.RegisterFunctionDelegate<object,float>();
        _app.DelegateManager.RegisterFunctionDelegate<UIElement, object, float>();
        _app.DelegateManager.RegisterFunctionDelegate<InputBox, int, char, char>();
        _app.DelegateManager.RegisterFunctionDelegate<TreeViewItem>();

        _app.RegisterCrossBindingAdaptor(new TVItemInheritanceAdaptor());
        _app.RegisterCrossBindingAdaptor(new TVNodeInheritanceAdaptor());
    }
    void RegProtobuf()
    {
        PType.RegisterILRuntimeCLRRedirection(_app);
    }
    public void Start(UIElement uiRoot, string Cmd, object data)
    {
        if (start != null)
        {
            try
            {
                _app.Invoke(mainScript.FullName, start.Name, mainScript, uiRoot, Cmd, data);
            }
            catch (Exception ex)
            {
                Debug.Log(ex.StackTrace);
            }
        }

    }
    public void RuntimeUpdate(float time)
    {
        if (Update != null)
        {
            try
            {
                _app.Invoke(mainScript.FullName, Update.Name, mainScript, time);
            }
            catch (Exception ex)
            {
                Debug.Log(ex.StackTrace);
            }
        }
    }
    public void RuntimeReSize()
    {
        if (Resize != null)
        {
            try
            {
                _app.Invoke(mainScript.FullName, Resize.Name, mainScript);
            }
            catch (Exception ex)
            {
                Debug.Log(ex.StackTrace);
            }
        }
    }
    public void RuntimeCmd(string cmd, string obj)
    {
        if (Cmd != null)
        {
            try
            {
                _app.Invoke(mainScript.FullName, Cmd.Name, mainScript, cmd, obj);
            }
            catch (Exception ex)
            {
                Debug.Log(ex.StackTrace);
            }
        }
    }
    public void RuntimeFullCmd(DataBuffer data)
    {
        if (Cmd != null)
        {
            try
            {
                _app.Invoke(mainScript.FullName, FullCmd.Name, mainScript, data);
            }
            catch (Exception ex)
            {
                Debug.Log(ex.StackTrace);
            }
        }
    }
    public void RuntimeDispose()
    {
        if (Dispose != null)
        {
            try
            {
                _app.Invoke(mainScript.FullName, Dispose.Name, mainScript);
            }
            catch (Exception ex)
            {
                Debug.Log(ex.StackTrace);
            }
        }
    }
    public void Clear()
    {

    }
}
